package combat;

import impsoft.bots.reflection.Interface;
import impsoft.bots.reflection.NPC;
import impsoft.bots.reflection.NPCIterator;
import impsoft.bots.reflection.Player;
import impsoft.bots.reflection.PlayerIterator;
import impsoft.bots.reflection.WorldObject;
import impsoft.scripting.ibot.structs.AryanTile;
import impsoft.scripting.ibot.structs.RGB;
import impsoft.scripting.ibot.structs.XY;
import impsoft.utils.general.Timer;
import impsoft.utils.ibot.ColorMapAnaylsis;

import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.List;

import tabs.TabHandler;
import base.DreamScript;
import base.DreamUtility;

public class CombatUtils extends DreamUtility {
	public boolean multi_combat = false;
	public List<NPC> npcs = new ArrayList<NPC>();

	public CombatUtils(DreamScript cs) {
		super(cs);
	}

	public boolean doSpecialAttack(String weaponSwitch) throws InterruptedException {
		if (!cs.theTabs.Attack.isSpecialAttackPainted() || cs.theTabs.Attack.getSpecialAttackPoints() == 0) {
			return false;
		}

		SpecialAttackWeapon weapon = getWieldedWeapon();
		SpecialAttackWeapon weapon2 = getWeapon(weaponSwitch);

		if (weapon2 == null && weapon != null
				&& cs.theTabs.Attack.getSpecialAttackPoints() >= weapon.getPointsRequired()) {
			return doSpecialAttack(weapon);
		}

		if (weapon2 != null && cs.theTabs.Attack.getSpecialAttackPoints() >= weapon2.getPointsRequired()) {
			SpecialAttackWeapon wieldedWeapon = getWieldedWeapon();
			boolean specSuccess = false;

			if (wieldedWeapon != null && wieldedWeapon.equals(weapon2)) {
				cs.getEquipmentUtils().putOnGear(new String[] { weapon2.getName() });

				specSuccess = doSpecialAttack(weapon2);

				cs.getEquipmentUtils().putOnGear(new String[] { wieldedWeapon.getName() });
			}

			return specSuccess;
		}

		return false;
	}

	public boolean doSpecialAttack(SpecialAttackWeapon weapon) throws InterruptedException {
		SpecialAttackWeapon wieldedWeapon = getWieldedWeapon();

		if (wieldedWeapon != null && wieldedWeapon.equals(weapon)) {
			String shield = null;
			if (wieldedWeapon.isTwoHanded()) {
				shield = cs.theTabs.Equipment.getShield();
			}

			if (!cs.theTabs.Attack.isSpecialAttackOn()) {
				cs.log("Clicking special attack");
				cs.theTabs.Attack.clickSpecialAttack();
			}

			for (Timer timer = new Timer(750); !timer.isUp() && !cs.theTabs.Attack.isSpecialEnabled();) {
				cs.sleep(100);
			}

			if (shield != null) {
				cs.getEquipmentUtils().putOnGear(new String[] { shield });
			}

			return cs.theTabs.Attack.isSpecialEnabled();
		}

		return false;
	}

	public SpecialAttackWeapon getWieldedWeapon() throws InterruptedException {
		return getWeapon(cs.getEquipmentUtils().getAllGear()[3]);
	}

	public SpecialAttackWeapon getWeapon(String weapon) {
		if (weapon == null) {
			return null;
		}

		for (SpecialAttackWeapon sa : SpecialAttackWeapon.values()) {
			if (sa.getName().toLowerCase().contains(weapon.toLowerCase())) {
				return sa;
			}
		}

		return null;
	}

	public boolean runawayFromCombat() {
		return false;
	}

	public NPC[] getMonstersInteractingWithMe() {
		List<NPC> npcs = new ArrayList<NPC>();
		NPCIterator iterator = cs.getNPCIterator();

		while (iterator.hasNext()) {
			NPC npc = iterator.next();

			if (npc.isInteractingWithMyPlayer()) {
				npcs.add(npc);
			}
		}

		return npcs.toArray(new NPC[npcs.size()]);
	}

	public NPC getNPC(AryanTile center, NPC ignore, int maxDistance, boolean obstacle, boolean onMiniMap, boolean free,
			Monster... monsters) throws InterruptedException {
		AryanTile myLocation = cs.getLocation();
		int bestDistance = Integer.MAX_VALUE;
		NPC bestNPC = null;

		if (monsters == null) {
			return null;
		}

		if (center == null) {
			center = myLocation;
		}

		npcs.clear();

		NPCIterator iterator = cs.getNPCIterator();
		while (iterator.hasNext()) {
			NPC npc = iterator.next();
			npcs.add(npc);

			monster: for (Monster monster : monsters) {
				if (monster.matches(npc) && (ignore == null || !npc.equals(ignore))) {
					AryanTile npcLocation = npc.getLocation();
					int distance = myLocation.distanceTo(npcLocation);
					int animation = npc.getAnimation();

					if (center.distanceTo(npcLocation) > maxDistance || distance == -1) {
						break monster;
					}

					/**
					 * if (onMiniMap && (!isOnMinimap(npc) &&
					 * npc.getLocation().distanceTo(cs.getLocation()) < 17)) {
					 * break monster; }
					 **/

					if (free && !isAttackable(npc)) {
						break monster;
					}

					if (obstacle && !cs.theMiniMap.canReachReflection(npcLocation)) {
						break monster;
					}

					if (npc.isInteractingWithMyPlayer() && animation != -1
							&& cs.getMyPlayer().getInteractingNPC() == null) {
						bestDistance = -1;
						bestNPC = npc;
					}

					if (distance < bestDistance) {
						bestDistance = distance;
						bestNPC = npc;
					}

					break monster;
				}
			}
		}

		return bestNPC;
	}

	public boolean isAttackable(NPC npc) throws InterruptedException {
		try {
			if (npc == null || npc.getLevel() < 1 || !npc.valid()) {
				return false;
			}

			if (npc.inCombat() && npc.getHPRatio() < 1) {
				return false;
			}

			if (multi_combat && isMultiCombatArea()) {
				return !isPlayerFightingNPC(npc) || npc.getHPRatio() > 130;
			} else {
				return !isPlayerFightingNPC(npc);
			}
		} catch (NullPointerException e) {
			e.printStackTrace();
		}

		return false;
	}

	public boolean isNPCAttacking(Player p) {
		NPCIterator iterator = cs.getNPCIterator();

		while (iterator.hasNext()) {
			NPC npc = iterator.next();
			Player interacted = npc.getInteractingPlayer();

			if (interacted != null && interacted.equals(p)) {
				return true;
			}
		}

		return false;
	}

	public boolean isOnMinimap(WorldObject object) throws InterruptedException {
		if (object == null) {
			return false;
		}

		XY point = cs.theMiniMap.toMiniMapReflection(object.getLocation());
		if (point == null) {
			return false;
		}

		try {
			return ColorMapAnaylsis.findRGB(cs.getColorMap(), new RGB(254, 254, 17), new Rectangle(point.x - 5,
					point.y - 5, 10, 10)) != null;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}

	public boolean isMultiplePlayersFightingNPC(NPC npc) {
		return getPlayersFightingNPC(npc).length > 0;
	}

	public int getNumPlayersFightingNPC(NPC npc) {
		return getPlayersFightingNPC(npc).length;
	}

	public boolean isPlayerFightingNPC(NPC npc) {
		return getPlayerFightingNPC(npc) != null;
	}

	public Player getPlayerFightingNPC(NPC npc) {
		for (PlayerIterator playerIterator = cs.getPlayerIterator(); playerIterator.hasNext();) {
			Player player = playerIterator.next();
			Player myPlayer = cs.getMyPlayer();
			if (player != null && myPlayer != null && !player.getName().equalsIgnoreCase(myPlayer.getName())) {
				NPC npc2 = player.getInteractingNPC();
				if (npc2 != null && npc.equals(npc2)) {
					return player;
				}
			}
		}

		return null;
	}

	public Player[] getPlayersFightingNPC(NPC npc) {
		List<Player> players = new ArrayList<Player>();
		for (PlayerIterator playerIterator = cs.getPlayerIterator(); playerIterator.hasNext();) {
			Player player = playerIterator.next();
			Player myPlayer = cs.getMyPlayer();
			if (player != null && myPlayer != null && !player.getName().equalsIgnoreCase(myPlayer.getName())) {
				NPC npc2 = player.getInteractingNPC();
				if (npc2 != null && npc.equals(npc2)) {
					players.add(player);
				}
			}
		}

		return players.toArray(new Player[players.size()]);
	}

	public boolean isMultiCombatArea() {
		return cs.getReflectionFields().multiCombat;
	}

	public boolean switchAttackMode(String mode, TabHandler tab) throws InterruptedException {
		if (!isAttackModeSelected(mode)) {
			tab.setTab(cs.theTabs.Attack);

			int attackOption = getAttackOption(mode);
			if (attackOption != -1) {
				cs.mouseClickLeft(getAttackStyleArea(attackOption));

				for (Timer selection = new Timer(1000); selection.isNotUp() && !isAttackModeSelected(mode);) {
					cs.sleep(100);
				}
			}
		}

		return isAttackModeSelected(mode);
	}

	public boolean isAttackModeSelected(String mode) {
		return getAttackOption(mode) == cs.getSettingArray()[43];
	}

	public Rectangle getAttackStyleArea(int option) {
		return new Rectangle(583 + 84 * (option % 2), 256 + 51 * (option / 2), 41, 27);
	}

	private int ATTACK_MODE_PARENT = 884;
	private int ATTACK_MODE_CHILD_1 = 31;
	private int ATTACK_MODE_CHILD_2 = 27;
	private int ATTACK_MODE_CHILD_3 = 25;
	private int ATTACK_MODE_CHILD_4 = 22;

	public int getAttackOption(String mode) {
		Interface mode1 = cs.getInterfaceAtIndex(ATTACK_MODE_PARENT, ATTACK_MODE_CHILD_1);
		Interface mode2 = cs.getInterfaceAtIndex(ATTACK_MODE_PARENT, ATTACK_MODE_CHILD_2);
		Interface mode3 = cs.getInterfaceAtIndex(ATTACK_MODE_PARENT, ATTACK_MODE_CHILD_3);
		Interface mode4 = cs.getInterfaceAtIndex(ATTACK_MODE_PARENT, ATTACK_MODE_CHILD_4);

		String text = null;
		if (mode1 != null) {
			text = mode1.getText();
			if (text != null && text.equalsIgnoreCase(mode)) {
				return 0;
			}
		}

		if (mode2 != null) {
			text = mode2.getText();
			if (text != null && text.equalsIgnoreCase(mode)) {
				return 1;
			}
		}

		if (mode3 != null) {
			text = mode3.getText();
			if (text != null && text.equalsIgnoreCase(mode)) {
				return 2;
			}
		}

		if (mode4 != null) {
			text = mode4.getText();
			if (text != null && text.equalsIgnoreCase(mode)) {
				return 3;
			}
		}

		return -1;
	}
}
